home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / QuickDraw GX / QuickDraw GX Info / QuickDraw GX Interfaces / Interfaces & Libraries / printing libraries / PicturesAndPICTLibrary.c < prev   
Encoding:
C/C++ Source or Header  |  1994-04-30  |  15.0 KB  |  503 lines  |  [TEXT/MPS ]

  1. /*
  2.     Libraries for dealing with pictures within PICTs
  3.     copyright © 1992 Apple Computer, Inc.
  4.     All rights reserved.
  5.     
  6.     
  7.     Routines in this library:
  8.         PictureToPICT         - creates a PICT with an embedded picture shape
  9.         DrawPictureOrProxy    - renders a PICT created with the above call
  10. */
  11. #include <Types.h>
  12. #include <Quickdraw.h>
  13. #include <ToolUtils.h>
  14. #include <Memory.h>
  15.  
  16. #include "graphics routines.h"
  17. #include "graphics toolbox.h"
  18. #include "math routines.h"
  19. #include "storage library.h"
  20. #include "offscreen library.h"
  21. #include "qd library.h"
  22.  
  23. //-----------------------------------------------------------------------------
  24. // INTERNAL TYPEDEFS AND DEFINES
  25. //-----------------------------------------------------------------------------
  26.  
  27. // IDs for the PicComments
  28. #define shapeSignature    'shpe'
  29. #define shapeBegin        500
  30. #define shapeEnd        501
  31.  
  32. // typedefs for the new PicComments
  33. typedef struct 
  34.     {
  35.     OSType        signature;        // always == shapeSignature
  36.     short        kind;            // always == shapeBegin
  37.     Rect        bounds;            // bounds of shape @ 72 dpi
  38.     char        data[1];        // flattened shape data, total size of record determines
  39.                                 // size
  40.     } ShapeBeginRecord, *ShapeBeginPtr, **ShapeBeginHdl;
  41.     
  42. typedef struct
  43.     {
  44.     OSType        signature;        // always == shapeSignature
  45.     short        kind;            // always == shapeEnd
  46.     } ShapeEndRecord, *ShapeEndPtr, **ShapeEndHdl;
  47.  
  48. // calling conventions for a comment bottleneck
  49. typedef pascal void (*CommentProcPtr)(short kind, short dataSize, Handle dataHandle);
  50.     
  51. //-----------------------------------------------------------------------------
  52. // GLOBAL VARIABLES
  53. //-----------------------------------------------------------------------------
  54. short        gAmRendering;                    // are we handing rendering through GX?
  55. short        gWereProcsInstalled;            // were there already procs installed, or did we add them?
  56.  
  57. Rect        gPicFrame;                        // original size of picture
  58. Rect        gDestRect;                        // new size of picture
  59. CQDProcs    gSavedProcs;                    // if there were procs installed, we save them here
  60.  
  61. //-----------------------------------------------------------------------------
  62. // INTERNAL ROUTINES
  63. //-----------------------------------------------------------------------------
  64. pascal void NilTextBottleneck(short count, Ptr textAddr, Point numer, Point denom)
  65. /*
  66.     This bottleneck just NOPs out anything passing through it.
  67. */
  68. {
  69.     #pragma unused (count,textAddr,numer,denom)
  70.     return;
  71.     
  72. } // NilTextBottleneck
  73. /* ------------------------------------------------------------------------    */
  74.  
  75. pascal void NilLineBottleneck(Point newPt)
  76. /*
  77.     This bottleneck just NOPs out anything passing through it.
  78. */
  79. {
  80.     #pragma unused (newPt)
  81.     return;
  82.     
  83. } // NilLineBottleneck
  84.  
  85. /* ------------------------------------------------------------------------    */
  86.  
  87. pascal void NilRectBottleneck(GrafVerb verb, Rect *r)
  88. /*
  89.     This bottleneck just NOPs out anything passing through it.
  90. */
  91. {
  92.     #pragma unused (verb,r)
  93.     return;
  94.     
  95. } // NilRectBottleneck
  96.  
  97. /* ------------------------------------------------------------------------    */
  98.  
  99. pascal void NilRRectBottleneck(GrafVerb verb,const Rect *r,short ovalWidth,short ovalHeight)
  100. /*
  101.     This bottleneck just NOPs out anything passing through it.
  102. */
  103. {
  104.     #pragma unused (verb,r,ovalWidth,ovalHeight)
  105.     
  106.     return;
  107.     
  108. } // NilRRectBottleneck
  109.  
  110. /* ------------------------------------------------------------------------    */
  111.  
  112. pascal void NilPolyBottleneck(GrafVerb verb,PolyHandle poly)
  113. /*
  114.     This bottleneck just NOPs out anything passing through it.
  115. */
  116. {
  117.     #pragma unused (verb,poly)
  118.     return;
  119.     
  120. } // NilPolyBottleneck
  121.  
  122. /* ------------------------------------------------------------------------    */
  123.  
  124. pascal void NilBitsBottleneck(const BitMap *srcBits,const Rect *srcRect,const Rect *dstRect, short mode,RgnHandle maskRgn)
  125. /*
  126.     This bottleneck just NOPs out anything passing through it.
  127. */
  128. {
  129.     #pragma unused (srcBits,srcRect,dstRect,mode,maskRgn);
  130.     return;
  131.     
  132. } // NilBitsBottleneck
  133.  
  134. /* ------------------------------------------------------------------------    */
  135.  
  136. pascal void RenderComment(short kind, short dataSize, Handle dataHandle)
  137. /*
  138.     This bottleneck routine gets called to detect the shapeBegin/shapeEnd pairs.
  139.     Within these pairs, all other bottlenecks will be NOPed out, and we'll
  140.     draw QuickDraw GX data instead.
  141. */
  142. {
  143.     GrafPtr            curPort;
  144.     CQDProcsPtr        grafProcs;
  145.     gxShape            theShape;
  146.     
  147.     GetPort(&curPort);
  148.  
  149.     switch (kind)
  150.         {
  151.         case shapeBegin:
  152.             // when we see the start comment, stop all QuickDraw drawing via the bottlenecks
  153.             grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
  154. #ifndef __powerc
  155.             grafProcs->textProc        = (Ptr) NilTextBottleneck;
  156.             grafProcs->lineProc        = (Ptr) NilLineBottleneck;
  157.             grafProcs->rectProc        = (Ptr) NilRectBottleneck;
  158.             grafProcs->rRectProc    = (Ptr) NilRRectBottleneck;
  159.             grafProcs->ovalProc        = (Ptr) NilRectBottleneck;
  160.             grafProcs->arcProc        = (Ptr) NilRRectBottleneck;
  161.             grafProcs->polyProc        = (Ptr) NilPolyBottleneck;
  162.             grafProcs->rgnProc        = (Ptr) NilPolyBottleneck;
  163.             grafProcs->bitsProc        = (Ptr) NilBitsBottleneck;
  164. #else
  165.             grafProcs->textProc        = NewQDTextProc( (ProcPtr) NilTextBottleneck );
  166.             grafProcs->lineProc        = NewQDLineProc( (ProcPtr) NilLineBottleneck );
  167.             grafProcs->rectProc        = NewQDRectProc( (ProcPtr) NilRectBottleneck );
  168.             grafProcs->rRectProc    = NewQDRRectProc( (ProcPtr) NilRRectBottleneck );
  169.             grafProcs->ovalProc        = NewQDOvalProc( (ProcPtr) NilRectBottleneck );
  170.             grafProcs->arcProc        = NewQDArcProc( (ProcPtr) NilRRectBottleneck );
  171.             grafProcs->polyProc        = NewQDPolyProc( (ProcPtr) NilPolyBottleneck );
  172.             grafProcs->rgnProc        = NewQDRgnProc( (ProcPtr) NilPolyBottleneck );
  173.             grafProcs->bitsProc        = NewQDBitsProc( (ProcPtr) NilBitsBottleneck );            
  174. #endif
  175.                 
  176.             // We now are in charge of this grafPort
  177.             gAmRendering = true;
  178.  
  179.             // remove the header from the shape data            
  180.             Munger(dataHandle, 0, nil, sizeof(OSType) + sizeof(short) + sizeof(Rect), (Ptr)2, 0);
  181.                         
  182.             
  183.             // place the shape within the current window    
  184.             {
  185.             gxViewPort    windowViewPort = GXGetWindowViewPort(FrontWindow());
  186.             
  187.             theShape = HandleToShape(dataHandle, 1, &windowViewPort );
  188.             }
  189.             
  190.             // move the shape into the correct position of the window
  191.             {
  192.             gxShape        clipShape;
  193.             gxRectangle    clipRect;
  194.             
  195.             GXScaleTransform(GXGetShapeTransform(theShape), 
  196.                 FixRatio(gDestRect.right - gDestRect.left,     gPicFrame.right - gPicFrame.left),
  197.                 FixRatio(gDestRect.bottom - gDestRect.top,     gPicFrame.bottom - gPicFrame.top),
  198.                 0, 0);
  199.             GXMoveShapeTo(theShape, ff(gDestRect.left), ff(gDestRect.top) );
  200.             
  201.             // clip against the draw area
  202.             clipRect.left     = ff(gDestRect.left);
  203.             clipRect.top     = ff(gDestRect.top);
  204.             clipRect.right     = ff(gDestRect.right);
  205.             clipRect.bottom = ff(gDestRect.bottom);
  206.             clipShape = GXNewRectangle(&clipRect);
  207.             GXSetShapeClip(theShape, clipShape);
  208.             GXDisposeShape(clipShape);
  209.             }
  210.             
  211.             // finally, draw the data and get rid of it once done
  212.             GXDrawShape(theShape);
  213.             GXDisposeShape(theShape);
  214.  
  215.             break;
  216.             
  217.         case shapeEnd:
  218.             
  219.             // when we see the end comment, we restore all of the bottlenecks
  220.             grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
  221.             grafProcs->textProc        = gSavedProcs.textProc;
  222.             grafProcs->lineProc        = gSavedProcs.lineProc;
  223.             grafProcs->rectProc        = gSavedProcs.rectProc;
  224.             grafProcs->rRectProc    = gSavedProcs.rRectProc;
  225.             grafProcs->ovalProc        = gSavedProcs.ovalProc;
  226.             grafProcs->arcProc        = gSavedProcs.arcProc;
  227.             grafProcs->polyProc        = gSavedProcs.polyProc;
  228.             grafProcs->rgnProc        = gSavedProcs.rgnProc;
  229.             grafProcs->bitsProc        = gSavedProcs.bitsProc;
  230.                 
  231. #ifdef __powerc
  232.             DisposeRoutineDescriptor( grafProcs->textProc );
  233.             DisposeRoutineDescriptor( grafProcs->lineProc );
  234.             DisposeRoutineDescriptor( grafProcs->rectProc );
  235.             DisposeRoutineDescriptor( grafProcs->rRectProc );
  236.             DisposeRoutineDescriptor( grafProcs->ovalProc );
  237.             DisposeRoutineDescriptor( grafProcs->arcProc );
  238.             DisposeRoutineDescriptor( grafProcs->polyProc );
  239.             DisposeRoutineDescriptor( grafProcs->rgnProc );
  240.             DisposeRoutineDescriptor( grafProcs->bitsProc );    
  241. #endif
  242.             // we're detached from the bottlenecks now
  243.             gAmRendering = false;
  244.             break;
  245.             
  246.         default:
  247.             // if we aren't rendering GX data yet, let the comment proc go through
  248.             if ( !(gAmRendering) )
  249.                 {
  250.                 if (gWereProcsInstalled)
  251.                     {
  252.                     // use the previously installed comment
  253.                     grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
  254.                     
  255.                     (* (CommentProcPtr) (gSavedProcs.commentProc)) (kind, dataSize, dataHandle);
  256.                     }
  257.                 else
  258.                     {
  259.                     // use the ROM comment proc - not that it normally does anything
  260.                     StdComment(kind, dataSize, dataHandle);
  261.                     }
  262.                 }
  263.             break;
  264.             
  265.         } // switch (kind)
  266.         
  267. } // RenderComment
  268.  
  269. //-----------------------------------------------------------------------------
  270. // EXTERNAL ROUTINES
  271. //-----------------------------------------------------------------------------
  272. void    DrawPictureOrProxy(PicHandle hPicture, Rect *dstRect)
  273. /*
  274.     This library routine demonstrates how to render a picture, such that GX proxies
  275.     (as generated through PictureToPICT) are rendered using GX rather than QuickDraw.
  276.     
  277.     This routine works by installing QuickDraw bottlenecks that interpret the data
  278.     in the PicComments to determine when GX data is to be used.
  279.     
  280.     This call assumes that a valid QuickDraw window exists, and that it has a valid
  281.     window viewPort - created by calling NewWindowViewPort.
  282. */
  283. {
  284. #ifdef __powerc
  285.     QDCommentUPP rendercomment = NewQDCommentProc((ProcPtr) RenderComment );
  286. #endif
  287.     
  288.     // so far, no GX data
  289.     gAmRendering = false;
  290.     
  291.     // remember where picture is being drawn (offset by the origin)
  292.     gPicFrame     = (**hPicture).picFrame;
  293.     gDestRect     = *dstRect;
  294.     OffsetRect(&gDestRect, -qd.thePort->portRect.left, -qd.thePort->portRect.top);
  295.     
  296.     // are there existing procs?
  297.     if (qd.thePort->grafProcs != nil)
  298.         {
  299.         // remember that there were orginally bottlenecks
  300.         gWereProcsInstalled = true;
  301.         
  302.         // save the old procs away
  303.         gSavedProcs = *((CQDProcs*)qd.thePort->grafProcs);
  304.         
  305.         // install our StdComment proc
  306. #ifndef __powerc
  307.         qd.thePort->grafProcs->commentProc =  (Ptr) RenderComment;
  308. #else
  309.         qd.thePort->grafProcs->commentProc = rendercomment;
  310. #endif
  311.         }
  312.     else
  313.         {
  314.         // no existing procs, so install new bottlenecks
  315.         gWereProcsInstalled = false;
  316.         
  317.         // install the standard procs
  318.         if (qd.thePort->portBits.rowBytes & 0x80000000)
  319.             SetStdCProcs(&gSavedProcs);
  320.         else
  321.             SetStdProcs((QDProcs*) &gSavedProcs);
  322.             
  323.         // and a custom comment proc
  324.         #ifndef __powerc
  325.             gSavedProcs.commentProc = (Ptr) RenderComment;
  326.         #else
  327.             gSavedProcs.commentProc = rendercomment;
  328.         #endif
  329.         
  330.         // stick the procs into the port
  331.         qd.thePort->grafProcs = (QDProcs*) &gSavedProcs;
  332.         }
  333.         
  334.     // render the data
  335.     DrawPicture(hPicture, dstRect);
  336.     
  337.     if (gWereProcsInstalled)
  338.         {
  339.         
  340.         // if there were originally bottlenecks in the port, replace them
  341.         if (qd.thePort->portBits.rowBytes & 0x80000000)
  342.             *(((CGrafPtr)qd.thePort)->grafProcs) = gSavedProcs;
  343.         else
  344.             *(qd.thePort->grafProcs) = * ((QDProcs*) &gSavedProcs);
  345.         }
  346.     else
  347.         {
  348.         
  349.         // deinstall our bottlenecks
  350.         qd.thePort->grafProcs = nil;
  351.         }
  352.         
  353. #ifdef __powerc
  354.     DisposeRoutineDescriptor( rendercomment );
  355. #endif
  356.                 
  357. } // DrawPictureOrProxy
  358.  
  359. //-----------------------------------------------------------------------------
  360. PicHandle    PictureToPICT(gxShape theShape, Boolean simpleProxy)
  361. /*
  362.     This library routine turns a QuickDraw GX™ shape into a QuickDraw PICT.
  363.     It does this using three steps:
  364.         1)  it emits a QuickDraw PicComment, and places the flattened GX data into
  365.             the comment.
  366.         2)    it converts the GX picture into a QuickDraw proxy.  It uses a rectangle
  367.             with an 'X' through it if simpleProxy is true.  Otherwise, it uses a 1 bit
  368.             bitmap rendition of the shape.
  369.         3)    it emits a QuickDraw PictComment, marking the end of the QuickDraw proxy.
  370.         
  371.     The resulting PICT can be cut & pasted, or saved into a PICT file.  On a system
  372.     with QuickDraw GX™ installed, the GX data will be used when printing.  
  373.     When printing on other systems, the QuickDraw proxy will be used.
  374.     
  375.     The proxy is always used for display from within non-GX applications.
  376. */
  377. {
  378.     gxGraphicsError        gxErr = noErr;
  379.     PicHandle            thePicture;
  380.     Rect                picRect;
  381.     ShapeBeginRecord    theBegin;
  382.     Handle                hBegin;
  383.     ShapeEndHdl            hEnd;
  384.     gxRectangle            shapeBounds;
  385.         
  386.     // get the location of the shape
  387.     GXGetShapeDeviceBounds(theShape, 0, 0, &shapeBounds);    
  388.     picRect.left     = FixedToInt(shapeBounds.left);
  389.     picRect.top     = FixedToInt(shapeBounds.top);
  390.     picRect.right     = FixedToInt(shapeBounds.right);
  391.     picRect.bottom     = FixedToInt(shapeBounds.bottom);
  392.     GlobalToLocal((Point*) &picRect.top);
  393.     GlobalToLocal((Point*) &picRect.bottom);
  394.         
  395.     thePicture = OpenPicture(&picRect);
  396.     if (thePicture != nil)
  397.         {
  398.         // use a standard clipping and pen mode
  399.         ClipRect(&picRect);
  400.         PenNormal();
  401.         
  402.         // flatten our shape out into a handle
  403.         hBegin = ShapeToHandle(theShape);
  404.         if (hBegin != nil)
  405.             {
  406.             // add the comment to the begining of the handle
  407.             theBegin.signature     = shapeSignature;
  408.             theBegin.kind         = shapeBegin;
  409.             theBegin.bounds     = picRect;
  410.             Munger(hBegin, 0, nil, 0, &theBegin, sizeof(OSType) + sizeof(short) + sizeof(Rect) );
  411.             gxErr = MemError();
  412.         
  413.             // store the shape/handle into the picture
  414.             PicComment(shapeBegin, GetHandleSize(hBegin), hBegin);
  415.             DisposHandle(hBegin);
  416.             
  417.             }
  418.         else
  419.             gxErr = MemError();
  420.     
  421.         if (gxErr == noErr)
  422.             {
  423.             if (simpleProxy)
  424.                 {
  425.                 // our proxy is just a framed rect with an X through it
  426.                 FrameRect(&picRect);
  427.                 MoveTo(picRect.left,     picRect.top);
  428.                 LineTo(picRect.right,     picRect.bottom);
  429.                 MoveTo(picRect.right,     picRect.top);
  430.                 LineTo(picRect.left,     picRect.bottom);
  431.                 }
  432.             else
  433.                 {
  434.                 // our proxy is a bitmap of the GX object
  435.                 gxBitmap        theBits;
  436.                 gxShape            theBitmap;
  437.  
  438.                 theBits.width         = picRect.right - picRect.left;
  439.                 theBits.height         = picRect.bottom - picRect.top;
  440.                 theBits.pixelSize     = 1;
  441.                 theBits.rowBytes    = ((theBits.width + 31) >> 5) << 2;
  442.                 theBits.image         = NewPtrClear(theBits.height * theBits.rowBytes);
  443.                 theBits.space         = gxIndexedSpace;
  444.                 theBits.set         = nil;
  445.                 theBits.profile     = nil;
  446.                 
  447.                 gxErr = MemError();
  448.                 if (gxErr == noErr)
  449.                     {
  450.                     theBitmap = GXNewBitmap(&theBits, nil);
  451.                     GXMoveTransformTo(GXGetShapeTransform(theBitmap), -shapeBounds.left, -shapeBounds.top);
  452.                     GXGetGraphicsError(&gxErr);
  453.                     if (gxErr == noErr)
  454.                         {
  455.                         BitMap        qdBits;
  456.                         
  457.                         // put the shape into the bitmap
  458.                         CopyToBitmaps(theBitmap, theShape);
  459.                         ConvertToQDBitmap(&theBits, &qdBits);
  460.                         GXGetGraphicsError(&gxErr);
  461.                                                                         
  462.                         // now done with the bitmap
  463.                         GXDisposeShape(theBitmap);
  464.  
  465.                         // CopyBits it into the picture
  466.                         CopyBits(&qdBits, &qd.thePort->portBits, &qdBits.bounds, &picRect, srcOr, nil);
  467.                         
  468.                         }
  469.                         
  470.                     // and done with the image
  471.                     DisposePtr(theBits.image);
  472.                     }
  473.                 }
  474.             
  475.             // mark the end of our shape's proxy
  476.             hEnd = (ShapeEndHdl) NewHandle(sizeof(ShapeEndRecord));
  477.             if (hEnd != nil)
  478.                 {
  479.                 (**hEnd).signature     = shapeSignature;
  480.                 (**hEnd).kind         = shapeEnd;
  481.                 PicComment(shapeEnd, GetHandleSize((Handle) hEnd), (Handle) hEnd);
  482.                 DisposHandle((Handle) hEnd);
  483.                 }
  484.             else
  485.                 gxErr = MemError();
  486.             }
  487.         
  488.         ClosePicture();
  489.         }
  490.     else
  491.         gxErr = MemError();
  492.         
  493.     // if we had a problem, return a nil picture
  494.     if ( ( gxErr != noErr ) && thePicture )
  495.         {
  496.         KillPicture(thePicture);
  497.         thePicture = nil;
  498.         }
  499.         
  500.     return(thePicture);
  501.     
  502. } // PictureToPICT
  503.